package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * 对称棋
 * （全新重构版本）
 */
public class SymmetricRoom extends Room {

    private ActionState actionState; //当前行动状态
    private List<Piece> pieceList; //棋盘上的棋子信息集合
    private List<List<Piece>> symmetryBlocksSet; //对称棋块集合
    private List<List<Piece>> asymmetricBlocksSet; //非对称棋块集合
    private List<Piece> pullAblePieceList;//可被拉的棋子的集合
    private List<Point> pullAbleEmptyList;//可被拉的空格的集合
    private Piece fallPiece; //最新落下的棋子
    private Piece pickPiece; //当前选中等待拉动的棋子
    private int[] pullOneArrowTip; //最新拉子箭头提示
    private int[] pullTwoArrowTip; //最新拉子箭头提示
    private boolean hasAsymmetry5BlocksOnStart; //记录行动前是否存在不对称5塔

    public SymmetricRoom(String roomName) {
        super(roomName,
                "从十年前开始，历经366版改进。\n目标是构造出漂亮的对称棋形。\n谁能把“对称”坚持到最后呢？",
                "对称棋",
                BoardStyleData.getGoBangStyle(15, 15),
                true,
                true);
    }

    @Override
    public String getRuleText() {
        return "【对称棋】规则\n" +
                "1. 棋盘与棋子：\n" +
                "    15x15棋盘，黑先白后，轮流行棋。\n" +
                "2. 落子与拉子：\n" +
                "    每次落一子（记为A子），还可以选一颗与A子（直or斜）同线的棋子，使它往A子方向拉动1格（如遇阻挡可跨越）。\n" +
                "    如果拉动的是单独的一子棋块，则拉动距离不限。也可以选择不拉子。\n" +
                "3. 棋块与对称：\n" +
                "    （直斜）相邻的同色棋子组成棋块。当一块棋能被一条对称轴（直斜）整体平分，则是对称棋块。\n" +
                "    行棋前，若行棋方有5子以上的不对称棋块，本次行棋可拉子两次。\n" +
                "4. 胜负判定：\n" +
                "    行棋后，行棋方有不对称棋块，判负。";
    }

    @Override
    public String getGameInfo() {
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        if (actionState != null) {
            //更新操作提示
            gameTip = actionState.getTip(cur == 1 ? "黑方" : "白方");
            //绘制场上棋子
            for (Piece piece : pieceList) {
                curGrids[piece.row][piece.col] = piece.side;
            }
            //绘制对称棋块 （黑or白半透明包围色团）
            for (List<Piece> symmetryBlock : symmetryBlocksSet) {
                List<Integer> signIds = new ArrayList<>();
                for (Piece piece : symmetryBlock) {
                    signIds.add(getIndex(piece.row, piece.col));
                }
                boolean isBlack = symmetryBlock.get(0).side == 1;
                signList.add(new AroundSign(new ArrayList<>(signIds), isBlack ? "#66000000" : "#66FFFFFF", isBlack ? "#AA000000" : "#AAFFFFFF", 1f));
            }
            //绘制非对称棋块 （红色半透明色团）
            for (List<Piece> asymmetricBlock : asymmetricBlocksSet) {
                List<Integer> signIds = new ArrayList<>();
                for (Piece piece : asymmetricBlock) {
                    signIds.add(getIndex(piece.row, piece.col));
                }
                signList.add(new AroundSign(new ArrayList<>(signIds), "#66FF0000", "#AAFF0000", 1f));
            }
            //绘制最近拉子提示1（淡红色箭头）
            if (pullOneArrowTip != null) {
                signList.add(new LineSign(pullOneArrowTip[0], pullOneArrowTip[1], ColorCost.MOVE_ARROW, 1));
            }
            //绘制最近拉子提示2（淡红色箭头）
            if (pullTwoArrowTip != null) {
                signList.add(new LineSign(pullTwoArrowTip[0], pullTwoArrowTip[1], ColorCost.MOVE_ARROW, 1));
            }
            //绘制最近落子后提示
            if (fallPiece != null) {
                //绘制最近落子提示（淡绿色底格）
                signList.add(new TextSign(getIndex(fallPiece.row, fallPiece.col), "◉", ColorCost.NEW_PUT_POINT));
                //绘制可被拉棋子高亮提示（朝向最近落子棋子的绿色箭头）
                if (pullAblePieceList != null) {
                    for (Piece pullAblePiece : pullAblePieceList) {
                        String pushArrTipStr = getPushArrTipStr(pullAblePiece, fallPiece);
                        signList.add(new TextSign(getIndex(pullAblePiece.row, pullAblePiece.col), pushArrTipStr, ColorCost.NEW_PUT_POINT));
                    }
                }
            }

            //绘制制当前选中拉子（绿色方框）和可拉位置路径（绿色小点）
            if (pickPiece != null) {
                //当前选中拉子
                signList.add(new TextSign(getIndex(pickPiece.row, pickPiece.col), "◎", ColorCost.NEW_PUT_POINT));
                //可拉位置路径
                if (pullAbleEmptyList != null) {
                    for (Point pullAbleEmpty : pullAbleEmptyList) {
                        signList.add(new TextSign(getIndex(pullAbleEmpty.y, pullAbleEmpty.x), "•", ColorCost.NEW_PUT_POINT));
                    }
                }
            }
        }
        return super.getGameInfo();
    }

    //根据可拉棋子和新落棋子之间的位置关系，获取拉子箭头提示文本符号
    private String getPushArrTipStr(Piece from, Piece to) {
        if (from.row == to.row && from.col < to.col) return "→";
        if (from.row == to.row && from.col > to.col) return "←";
        if (from.col == to.col && from.row < to.row) return "↓";
        if (from.col == to.col && from.row > to.row) return "↑";
        if (from.row < to.row && from.col < to.col) return "↘";
        if (from.row < to.row && from.col > to.col) return "↙";
        if (from.row > to.row && from.col < to.col) return "↗";
        if (from.row > to.row && from.col > to.col) return "↖";
        return "";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        gameTip = "-1";
        actionState = null;
        pieceList = null;
        symmetryBlocksSet = null;
        asymmetricBlocksSet = null;
        pullAblePieceList = null;
        pickPiece = null;
        fallPiece = null;
        pullOneArrowTip = null;
        pullTwoArrowTip = null;
        hasAsymmetry5BlocksOnStart = false;
    }

    @Override
    protected void onStartPrepare() {
        actionState = ActionState.WAIT_FALL; //初始设置
        pieceList = new ArrayList<>();
        symmetryBlocksSet = new ArrayList<>();
        asymmetricBlocksSet = new ArrayList<>();
        noticeBlackMove();
    }

    @Override
    public void doRule(int row, int col, int value) {
        //根据坐标获取该位置的信息，为null就是空位置，不为空就是已有棋子了
        Piece piece = getPieceByPoint(col, row);
        //等待落子
        if (checkState(ActionState.WAIT_FALL)) {
            if (piece == null) {
                hasAsymmetry5BlocksOnStart = checkHasAsymmetry5Blocks(value); //落子前记录是否有非对称的大塔（决定本次行动接下来是否可以拉子2次）
                fallPiece(row, col, value); //落下黑棋子
                pullAblePieceList = getPullAblePieceList();//获取可拉棋子
                //存在可拉棋子时
                if (pullAblePieceList != null) {
                    if (hasAsymmetry5BlocksOnStart) {
                        changeState(ActionState.PICK_ONE); //可拉两次,切换到拉第一次
                    }
                    else {
                        changeState(ActionState.PICK_TWO); //只可拉一次，就直接跳到拉第二次（业务逻辑是一样的）
                    }
                }
                //无可拉棋子时
                else {
                    //行动结束时，己方存在非对称棋块
                    if (checkHasAsymmetryBlocks(value)) {
                        changeState(ActionState.FINAL_WIN); //存在就切换到结束状态
                    }
                    //己方行动完成，游戏没有结束
                    else {
                        changeState(ActionState.WAIT_FALL); //切换到等待落子状态
                    }
                }
            }
        }
        //选择第一个可拉棋子
        else if (checkState(ActionState.PICK_ONE)) {
            //选中了可拉棋子
            if (pullAblePieceList.contains(piece)) {
                pickPiece = piece;
                pullAbleEmptyList = getPullAbleEmptyList();//获取可拉空格
                changeState(ActionState.PULL_ONE);
            }
            //点击了不能拉子的地方
            else {
                //放弃拉子，检查游戏是否结束
                pullAblePieceList = null;
                //行动结束时，己方存在非对称棋块
                if (checkHasAsymmetryBlocks(value)) {
                    changeState(ActionState.FINAL_WIN); //存在就切换到结束状态
                }
                //己方行动完成，游戏没有结束
                else {
                    changeState(ActionState.WAIT_FALL); //切换到等待落子状态
                }
            }
        }
        //拉动第一个棋子位置到
        else if (checkState(ActionState.PULL_ONE)) {
            //选中了别的可拉棋子
            if (pullAblePieceList.contains(piece)) {
                pickPiece = piece; //切换选中棋子
                pullAbleEmptyList = getPullAbleEmptyList(); //重新获取可拉空格
                changeState(ActionState.PULL_ONE); //继续选择拉动位置
            }
            //选中了可拉位置
            else if (isPullAbleEmpty(row, col)) {
                pullPiece(row, col, true); //执行拉子方法
                pullAblePieceList = getPullAblePieceList();//获取可拉棋子
                changeState(ActionState.PICK_TWO); //选择拉第二个棋子
            }
            //选中了不可拉子的位置
            else {
                pickPiece = null;
                pullAbleEmptyList = null;
                changeState(ActionState.PICK_ONE); //切换回拉子状态？
            }
        }
        //选择第二个可拉棋子
        else if (checkState(ActionState.PICK_TWO)) {
            //选中了可拉棋子
            if (pullAblePieceList.contains(piece)) {
                pickPiece = piece;
                pullAbleEmptyList = getPullAbleEmptyList(); //重新获取可拉空格
                changeState(ActionState.PULL_TWO);
            }
            //点击了不能拉子的地方
            else {
                //放弃拉子，检查游戏是否结束
                pullAblePieceList = null;
                //行动结束时，己方存在非对称棋块
                if (checkHasAsymmetryBlocks(value)) {
                    changeState(ActionState.FINAL_WIN); //存在就切换到结束状态
                }
                //己方行动完成，游戏没有结束
                else {
                    changeState(ActionState.WAIT_FALL); //切换到等待落子状态
                }
            }
        }
        //拉动第二个棋子位置到
        else if (checkState(ActionState.PULL_TWO)) {
            //选中了别的可拉棋子
            if (pullAblePieceList.contains(piece)) {
                pickPiece = piece; //切换选中棋子
                pullAbleEmptyList = getPullAbleEmptyList(); //重新获取可拉空格
                changeState(ActionState.PULL_TWO); //继续选择拉动位置
            }
            //选中了可拉位置
            else if (isPullAbleEmpty(row, col)) {
                pullPiece(row, col, false); //执行拉子方法
                //行动结束时，己方存在非对称棋块
                if (checkHasAsymmetryBlocks(value)) {
                    changeState(ActionState.FINAL_WIN); //存在就切换到结束状态
                }
                //己方行动完成，游戏没有结束
                else {
                    changeState(ActionState.WAIT_FALL); //切换到等待落子状态
                }
            }
            //选中了不可拉子的位置
            else {
                pickPiece = null;
                pullAbleEmptyList = null;
                changeState(ActionState.PICK_TWO); //切换回拉子状态？
            }
        }
    }

    //判断当前位置是否可拉空格
    private boolean isPullAbleEmpty(int row, int col) {
        for (Point point : pullAbleEmptyList) {
            if (point.x == col && point.y == row) {
                return true;
            }
        }
        return false;
    }

    //根据坐标点获取棋子
    private Piece getPieceByPoint(int pCol, int pRow) {
        for (Piece piece : pieceList) {
            if (piece.col == pCol && piece.row == pRow) {
                return piece;
            }
        }
        return null;
    }

    //判断当前状态
    private boolean checkState(ActionState state) {
        return state == actionState;
    }

    //切换状态
    private void changeState(ActionState state) {
        actionState = state;
        if (checkState(ActionState.WAIT_FALL)) {
            stepAdd();
            if (cur == 1) {
                noticeWhiteMove();
            }
            else if (cur == 2) {
                noticeBlackMove();
            }
        }
        else if (checkState(ActionState.FINAL_WIN)) {
            stepAdd();
            if (cur == 1) {
                doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白战胜" + player_black.getNickNameOrTemp());
            }
            else if (cur == 2) {
                doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑战胜" + player_white.getNickNameOrTemp());
            }
        }
        else {
            noticeAllRefreshGameInfo();
        }
    }

    //检查是否存在非对称的棋块
    private boolean checkHasAsymmetryBlocks(int side) {
        for (List<Piece> block : asymmetricBlocksSet) {
            if (block.get(0).side == side) {
                return true;
            }
        }
        return false;
    }

    //检查是否存在非对称的5个棋子以上的棋块
    private boolean checkHasAsymmetry5Blocks(int side) {
        for (List<Piece> block : asymmetricBlocksSet) {
            if (block.size() >= 5 && block.get(0).side == side) {
                return true;
            }
        }
        return false;
    }

    //根据最近落下的棋子获取可拉棋子
    private List<Piece> getPullAblePieceList() {
        List<Piece> pullAblePieces = new ArrayList<>();

        // 遍历所有棋子，找到与fallPiece共线的棋子
        for (Piece piece : pieceList) {
            // 跳过刚落下的棋子本身
            if (piece.no == fallPiece.no) {
                continue;
            }

            // 检查是否共线：直线或斜线
            if (piece.col == fallPiece.col || piece.row == fallPiece.row || Math.abs(piece.col - fallPiece.col) == Math.abs(piece.row - fallPiece.row)) {
                pullAblePieces.add(piece);
            }
        }

        return pullAblePieces.isEmpty() ? null : pullAblePieces;
    }

    //根据所选可拉棋子获得可以拉到的空格
    private List<Point> getPullAbleEmptyList() {
        List<Point> emptyList = new ArrayList<>();

        if (pickPiece == null || fallPiece == null) {
            return emptyList;
        }

        // 获取pickPiece所在的棋块
        List<Piece> pickPieceBlock = findPieceBlock(pickPiece);
        boolean isSinglePieceBlock = (pickPieceBlock != null && pickPieceBlock.size() == 1);

        // 获取从pickPiece到fallPiece方向的射线上的空格
        int deltaRow = fallPiece.row - pickPiece.row;
        int deltaCol = fallPiece.col - pickPiece.col;

        // 计算方向向量（单位化）
        int stepRow = 0, stepCol = 0;
        if (deltaRow != 0) {
            stepRow = deltaRow > 0 ? 1 : -1;
        }
        if (deltaCol != 0) {
            stepCol = deltaCol > 0 ? 1 : -1;
        }

        // 特殊情况：如果两个棋子位置相同，返回空列表
        if (stepRow == 0 && stepCol == 0) {
            return emptyList;
        }

        // 沿着射线方向查找空格
        int currentRow = pickPiece.row + stepRow;
        int currentCol = pickPiece.col + stepCol;

        while (currentRow >= 0 && currentRow < curGrids.length &&
                currentCol >= 0 && currentCol < curGrids[0].length) {

            // 检查当前位置是否为空格
            if (curGrids[currentRow][currentCol] == 0) {
                emptyList.add(new Point(currentCol, currentRow));

                // 如果棋块中只有一个棋子，继续查找更多空格
                // 否则只返回第一个空格
                if (!isSinglePieceBlock) {
                    break;
                }
            }
            currentRow += stepRow;
            currentCol += stepCol;
        }

        return emptyList;
    }

    // 查找棋子所在的棋块
    private List<Piece> findPieceBlock(Piece piece) {
        // 在对称棋块中查找
        for (List<Piece> block : symmetryBlocksSet) {
            if (block.contains(piece)) {
                return block;
            }
        }
        return null;
    }

    //落子方法
    private void fallPiece(int row, int col, int side) {
        Piece newPiece = new Piece(pieceList.size(), side, row, col); //因为pieceList里的棋子只增不减，所以可以用pieceList.size()来表示序号
        pieceList.add(newPiece); //添加棋子到场上
        fallPiece = newPiece; //记录最近落子
        checkSymmetryShape(); //检查局面对称情况（核心算法）
        pullOneArrowTip = null; //新落子时删除上一步的拉子提示
        pullTwoArrowTip = null; //新落子时删除上一步的拉子提示
    }

    //拉子方法
    private void pullPiece(int toRow, int toCol, boolean isOne) {
        int fromRow = pickPiece.row;
        int fromCol = pickPiece.col;
        pickPiece.row = toRow; //移动棋子
        pickPiece.col = toCol; //移动棋子
        pickPiece = null;
        pullAblePieceList = null;
        pullAbleEmptyList = null;
        checkSymmetryShape();//检查局面对称情况（核心算法）
        if (isOne) {
            pullOneArrowTip = new int[]{getIndex(fromRow, fromCol), getIndex(toRow, toCol)};
        }
        else {
            pullTwoArrowTip = new int[]{getIndex(fromRow, fromCol), getIndex(toRow, toCol)};
        }
    }

    //（核心算法）检查对称图形
    private void checkSymmetryShape() {
        //定义每个棋子和所在的棋块组合的关系结构
        Map<Piece, Set<Piece>> adjacentGroup = new HashMap<>();
        for (Piece key : pieceList) {
            Set<Piece> set = new HashSet<>();
            set.add(key);
            adjacentGroup.put(key, set);
        }

        //使用并查集算法合并相邻的同色棋子
        for (int i = 0; i < pieceList.size(); i++) {
            Piece pieceA = pieceList.get(i);
            for (int j = i + 1; j < pieceList.size(); j++) {
                Piece pieceB = pieceList.get(j);
                //如果两个棋子相邻且同色，合并它们所在的集合
                if (isAdjacent(pieceA, pieceB)) {
                    Set<Piece> setA = adjacentGroup.get(pieceA);
                    Set<Piece> setB = adjacentGroup.get(pieceB);

                    //如果两个集合不同，合并它们
                    if (setA != setB) {
                        //将较小的集合合并到较大的集合中，提高效率
                        if (setA.size() < setB.size()) {
                            setB.addAll(setA);
                            //更新所有在setA中的棋子的引用
                            for (Piece piece : setA) {
                                adjacentGroup.put(piece, setB);
                            }
                        }
                        else {
                            setA.addAll(setB);
                            //更新所有在setB中的棋子的引用
                            for (Piece piece : setB) {
                                adjacentGroup.put(piece, setA);
                            }
                        }
                    }
                }
            }
        }

        //收集所有独立的棋块（去重）
        Set<Set<Piece>> uniqueBlocks = new HashSet<>(adjacentGroup.values());

        //清空之前的棋块集合
        symmetryBlocksSet.clear();
        asymmetricBlocksSet.clear();

        //对每个独立的棋块检查对称性
        for (Set<Piece> block : uniqueBlocks) {
            List<Piece> blockList = new ArrayList<>(block);
            if (isSymmetryBlock(blockList)) {
                symmetryBlocksSet.add(blockList);
            }
            else {
                asymmetricBlocksSet.add(blockList);
            }
        }
    }

    //简单的对称性检查方法（临时实现，后续可以完善）
    private boolean isSymmetryBlock(List<Piece> block) {
        if (block.size() <= 1) {
            return true; // 单个棋子或空块视为对称
        }

        // 计算棋块的边界框
        int minCol = Integer.MAX_VALUE, maxCol = Integer.MIN_VALUE;
        int minRow = Integer.MAX_VALUE, maxRow = Integer.MIN_VALUE;

        for (Piece piece : block) {
            minCol = Math.min(minCol, piece.col);
            maxCol = Math.max(maxCol, piece.col);
            minRow = Math.min(minRow, piece.row);
            maxRow = Math.max(maxRow, piece.row);
        }

        // 计算中心点
        float midCol = (minCol + maxCol) / 2f;
        float midRow = (minRow + maxRow) / 2f;

        // 检查四种对称性，只要有一种成立就返回true
        return checkHorizontalSymmetry(block, midCol) ||
                checkVerticalSymmetry(block, midRow) ||
                checkPositiveSymmetry(block, midCol, midRow) ||
                checkNegativeSymmetry(block, midCol, midRow);
    }

    // 检查水平对称（垂直轴对称）
    private boolean checkHorizontalSymmetry(List<Piece> block, float midCol) {
        Set<Point> blockSet = new HashSet<>();
        for (Piece piece : block) {
            blockSet.add(new Point(piece.col, piece.row));
        }

        Set<Point> left = new HashSet<>();
        Set<Point> right = new HashSet<>();

        for (Point point : blockSet) {
            if (point.x < midCol) {
                left.add(point);
                float diff = midCol - point.x; // 计算要翻转的值
                point.x = (int) (midCol + diff); // 翻转坐标
            }
            else if (point.x > midCol) {
                right.add(point);
            }
        }

        return isSameCoordinate(left, right); // 判断两组棋子横纵坐标是否全等
    }

    // 检查垂直对称（水平轴对称）
    private boolean checkVerticalSymmetry(List<Piece> block, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (Piece piece : block) {
            blockSet.add(new Point(piece.col, piece.row));
        }

        Set<Point> top = new HashSet<>();
        Set<Point> bottom = new HashSet<>();

        for (Point point : blockSet) {
            if (point.y < midRow) {
                top.add(point);
                float diff = midRow - point.y; // 计算要翻转的值
                point.y = (int) (midRow + diff); // 翻转坐标
            }
            else if (point.y > midRow) {
                bottom.add(point);
            }
        }

        return isSameCoordinate(top, bottom);
    }

    // 检查正斜45°对称（y = -x + b 对称）
    private boolean checkPositiveSymmetry(List<Piece> block, float midCol, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (Piece piece : block) {
            blockSet.add(new Point(piece.col, piece.row));
        }

        Set<Point> leftTop = new HashSet<>();
        Set<Point> rightBottom = new HashSet<>();
        float split = midCol + midRow;

        for (Point point : blockSet) {
            if (point.y + point.x < split) {
                leftTop.add(point);
                // 先求两条直线的交点
                float b = midCol + midRow; // 根据公式y = ax + b; a=-1; 求对称线的公式需要的参数
                float h = point.y - point.x; // 求对齐线的公式需要的参数
                float jX = (b - h) / 2; // 求出垂线交点x
                float jY = (b + h) / 2; // 求出垂线交点y
                float diffX = jX - point.x;
                point.x = (int) (jX + diffX);
                float diffY = jY - point.y;
                point.y = (int) (jY + diffY);
            }
            else if (point.y + point.x > split) {
                rightBottom.add(point);
            }
        }

        return isSameCoordinate(leftTop, rightBottom);
    }

    // 检查负斜45°对称（y = x + b 对称）
    private boolean checkNegativeSymmetry(List<Piece> block, float midCol, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (Piece piece : block) {
            blockSet.add(new Point(piece.col, piece.row));
        }

        // 先全部水平翻转，这样midCol和midRow不会变，而变成可以以正45°斜线对称了
        Set<Point> left = new HashSet<>();
        Set<Point> right = new HashSet<>();

        for (Point point : blockSet) {
            if (point.x < midCol) {
                left.add(point);
                float diff = midCol - point.x;
                point.x = (int) (midCol + diff);
            }
            else if (point.x > midCol) {
                right.add(point);
                float diff = point.x - midCol;
                point.x = (int) (midCol - diff); // 还原改变
            }
        }

        Set<Point> leftTop = new HashSet<>();
        Set<Point> rightBottom = new HashSet<>();
        float split = midCol + midRow;

        for (Point point : blockSet) {
            if (point.y + point.x < split) {
                leftTop.add(point);
                float b = midCol + midRow; // 根据公式y = ax + b; a=-1; 求对称线的公式需要的参数
                float h = point.y - point.x; // 求对齐线的公式需要的参数
                float jX = (b - h) / 2; // 求出垂线交点x
                float jY = (b + h) / 2; // 求出垂线交点y
                float diffX = jX - point.x;
                point.x = (int) (jX + diffX);
                float diffY = jY - point.y;
                point.y = (int) (jY + diffY);
            }
            else if (point.y + point.x > split) {
                rightBottom.add(point);
            }
        }

        return isSameCoordinate(leftTop, rightBottom);
    }

    // 判断两组棋子横纵坐标是否全等
    private boolean isSameCoordinate(Set<Point> aSet, Set<Point> bSet) {
        if (aSet.size() != bSet.size()) {
            return false;
        }

        for (Point pointA : aSet) {
            boolean found = false;
            for (Point pointB : bSet) {
                if (pointA.x == pointB.x && pointA.y == pointB.y) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                return false;
            }
        }
        return true;
    }

    //判断两个棋子是否八方相邻
    private boolean isAdjacent(Piece a, Piece b) {
        if (a.no == b.no) return false; //同一个棋子直接判否
        if (a.side != b.side) return false; //不同阵营的棋子直接判否
        return Math.abs(a.col - b.col) <= 1 && Math.abs(a.row - b.row) <= 1;
    }

    /**
     * 行棋状态
     */
    private enum ActionState {
        WAIT_FALL("等待{side}落子..."),
        PICK_ONE("选择第一个可拉棋子..."),
        PULL_ONE("选择第一个棋子可拉动位置..."),
        PICK_TWO("选择最后一个可拉棋子..."),
        PULL_TWO("选择最后一个棋子可拉动位置..."),
        FINAL_WIN("对弈结束！");

        public final String tip;

        /**
         * 获取当前状态对应的操作提示
         */
        public String getTip(String side) {
            return tip.replace("{side}", side);
        }

        ActionState(String tip) {
            this.tip = tip;
        }
    }

    /**
     * 棋子信息
     */
    private static class Piece {

        public int no; //棋子编号，按照落子顺序编号，可以绘制手顺，可以排序防止包围光效混乱
        public int side; //棋子颜色，1黑，2白
        public int row;
        public int col;

        public Piece(int no, int side, int row, int col) {
            this.side = side;
            this.row = row;
            this.col = col;
            this.no = no;
        }
    }
}
